<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JS 相关练习</title>
</head>

<body>
    <script>
        // 用js递归的方式写1到100求和？
        function add(num1, mum2) {
            let num = num1 + mum2
            // 找到递归结束的点 递归结束是即最后一个数再加1大于100了此时直接把和返回即可
            if (mum2 + 1 > 100) {
                return num
            } else {
                // 前面相加数的和 加上 后面一个数
                return add(num, mum2 + 1)
            }
        }
        let sum = add(1, 2)
        console.log('sum', sum)


        // ES6 
        // 1、let const var let const 在自己的代码块中有效
        // 以下通过for循环为每个a[i] 元素设置为了一个函数 ，函数里面打印log 查看i 值
        //var 定义 i
        var a = [];
        for (var i = 0; i < 10; i++) {
            a[i] = function () {
                console.log('var::', i)
            }
        }

        a[6]() // 打印10
        //以上 i 是var 声明的 ，在全局范围内有效，所以全局只有一个变量i 每一次循环都会变化一次，最终变化到10，在for 循环完成后i 的值已经为10 了 ，所以调用a[6]()依然输出的是10.
        // let 定义 i
        var a = [];
        for (let i = 0; i < 10; i++) {
            a[i] = function () {
                console.log("let::", i)
            }
        }
        a[6]() // 打印6
        //以上i 是let 声明，当前的i 只在本轮循环有效，因此每次循环的i 都是一个新的变量，至于怎么记住上次的内容的，是JavaScript引擎记住的。
        for (let i = 0; i < 3; i++) {
            let i = 'abc'
            console.log(i)
        }
        // 另外，for循环还有一个特别之处，就是设置循环变量的那部分是一个父作用域，而循环体内部是一个单独的子作用域。这表明函数内部的变量i与循环变量i不在同一个作用域，有各自单独的作用域。
        for (var i = 0; i < 3; i++) {
            var i = 'hahaha'
            console.log(i)
        }
        // 以上整个i 的值变了之后循环就进行不下去了 所以只打印一次


        // let 声明的变量不存在变量提升,let 生命的变量要先声明在使用 ，不像var


        // 暂时性死区
        // 只要块级作用域内存在let命令，它所声明的变量就绑定（binding）这个区域，不再受外界的影响
        // var tmp = 123
        // if (true) {
        //     console.log(tmp) //index.html:68 Uncaught ReferenceError: Cannot access 'tmp' before initialization
        //     let tmp = 'haha'
        // }

        // // 不允许重复声明 let 不允许在同一个作用域内重复声明一个变量
        // function func() {
        //     let a = 'aaa'
        //     var a = 'a' //Uncaught SyntaxError: Identifier 'a' has already been declared
        // }


        // function funcc() {
        //     let a = 'aaa'
        //     let a = '4' //Uncaught SyntaxError: Identifier 'a' has already been declared
        // }




        //2 块级作用域
        console.log('----块级作用域-----')
        var tmp = new Date();

        function f() {
            console.log(tmp);
            if (false) {
                var tmp = 'hello world';
            }
        }

        f(); // undefined  以上内层变量覆盖外层变量 本来想打印得到data 值 结果却是undefined


        //第二种场景，用来计数的循环变量泄露为全局变量。
        var s = 'hello';

        for (var i = 0; i < s.length; i++) {
            console.log(s[i]);
        }

        console.log(i); // 5
        //上面代码中，变量i只用来控制循环，但是循环结束后，它并没有消失，泄露成了全局变量。

        // 块级作用域与函数声明

        // if(true) let x = 1// 报错 因为let 只能出现在当前作用域的顶层 ，块级作用域 以大括号为准
        if (true) {
            let x = 1
        }

        // 函数声明也是如此 在严格模式下，函数只能声明在块级作用域的顶层
        // 不报错
        'use strict';
        if (true) {
            function f() {}
        }

        // 报错
        'use strict';
        if (true)

        function f() {}



        // 顶层对象属性

        var a = 1;
        // 如果在 Node 的 REPL 环境，可以写成 global.a
        // 或者采用通用方法，写成 this.a
        window.a // 1

        let b = 1;
        window.b // undefined
    </script>
</body>

</html>